#pragma once

#include "rendering/GameRenderer.h"
#include "rendering/Camera.h"
#include "GameObjects/GameObject.h"
#include "GameObjects/Sphere.h"
#include "GameObjects/Cube.h"
#include "GameObjects/Puck.h"
#include "GameObjects/Cylinder.h"
#include "GameObjects/Paddle.h"
#include "GameObjects/WallTile.h"
#include "GameObjects/WallLight.h"
#include "GameObjects/MjpegCamera.h"
#include "GameObjects/LightBase.h"
#include "GameObjects/PointLight.h"
#include "Utilities/GameTimer.h"
#include "Audio/AudioEngine.h"
#include "MainPage.xaml.h"

ref class GameRenderer;

ref class GameEngine
{
internal:
	GameEngine();

	void SplitPucks();
	void Score(Coding4Fun::Maelstrom::Common::Player playerWhoScored, Puck^ puck);
	void Initialize(_In_ GameRenderer^ render, Coding4Fun::Maelstrom::GameConsole::MainPage^ page);
	void GameTick();
	void FirePuck(int puckNum, Coding4Fun::Maelstrom::Common::Player player);
	void SetGameState(Coding4Fun::Maelstrom::Common::GameState gameState);
	void HandleControllerInput(Coding4Fun::Maelstrom::Communication::UserInputPacket^ packet, Coding4Fun::Maelstrom::Common::Player player);
	void HandleMusicTransition(int score);
	void ConnectToConsole1();

	__forceinline std::vector<GameObject^> RenderObjects()	{ return m_renderObjects; };
	__forceinline std::vector<GameObject^> TransparentRenderObjects() { return m_transparentRenderObjects; };

	__forceinline Camera^ GameCamera()						{ return m_camera; };

	__forceinline Paddle^ Paddle1()							{ return m_paddle1; };
	__forceinline Paddle^ Paddle2()							{ return m_paddle2; };

	__forceinline GameTimer^ GetGameTimer()					{ return m_timer; }

	__forceinline bool IsLoaded()                           { return m_loaded; }

	__forceinline float DamageTimer()						{ return m_damageTimer; }

	__forceinline bool IsPlayerOne() { return m_player == Coding4Fun::Maelstrom::Common::Player::One; }

	std::vector<Puck^> GetPucks()                           { return m_pucks; }

	Coding4Fun::Maelstrom::GameConsole::MainPage^ GetMainPage() { return m_page; }

	__forceinline bool MjpegStation() { return m_mjpegStation; }
	void MjpegStation(bool enabled);

private:
	std::vector<WallTile^>						m_environmentCollisionWalls;

	GameRenderer^                               m_renderer;
	Coding4Fun::Maelstrom::GameConsole::MainPage^ m_page;
	Coding4Fun::Maelstrom::Common::Player		m_player;

	DirectX::XMFLOAT3                           m_defaultEyePosition;
	DirectX::XMFLOAT3                           m_defaultLookAt;

	Camera^										m_camera;

	std::vector<GameObject^>                    m_renderObjects;
	std::vector<GameObject^>					m_transparentRenderObjects;
	std::vector<Puck^>							m_pucks;

	Paddle^										m_paddle1;
	Paddle^										m_paddle2;

	bool										m_player1Ready;
	bool										m_player2Ready;

	Coding4Fun::Maelstrom::Common::Player		m_winner;

	MjpegCamera^								m_player1Camera;
	MjpegCamera^								m_player2Camera;

	float										m_resetTimer;

	int											m_player1Score;
	int											m_player2Score;
	Coding4Fun::Maelstrom::Common::Player		m_puckAttachedTo;

	Coding4Fun::Maelstrom::Communication::SocketListener^	m_controllerListener1;
	Coding4Fun::Maelstrom::Communication::SocketListener^	m_controllerListener2;

	Coding4Fun::Maelstrom::Communication::IGamePacket^		m_lastPacket1;
	Coding4Fun::Maelstrom::Communication::IGamePacket^		m_lastPacket2;

	Coding4Fun::Maelstrom::Communication::SocketListener^	m_consoleListener;
	Coding4Fun::Maelstrom::Communication::SocketClient^		m_consoleClient;

	Coding4Fun::Maelstrom::Common::HardwareCommunication^	m_hardware;

	Coding4Fun::Maelstrom::Common::GameState				m_gameState;

	AudioEngine^								m_audioEngine;
	GameTimer^                                  m_timer;

	int											m_countDownStep;

	bool										m_loaded;

	double										m_launchTimer;

	std::vector<std::vector<WallLight^>>		m_wallLights;
	std::vector<std::vector<WallTile^>>			m_wallTiles;

	std::vector<WallTile^> m_currentSplitTiles;
	int m_segments[4];

	bool m_splitActive;

	float										m_gameResultsAnimationTimer;
	int											m_segmentIndex;
	int											m_direction;
	float										m_powerupTimer;
	float										m_damageTimer;

	bool										m_mjpegStation;

	void CreateGameObjects();
	void ResetPucks();
	void UpdatePucks();
	bool AnyPucksActive();
	void SplitPucks(Puck^ activePuck);
	void HandleCountdown();
	void ResetCountdown();

	bool CheckPuckPaddleCollision(Puck^ puck, Paddle^ paddle);
	bool CheckWallCollision(Puck^ puck);

	Coding4Fun::Maelstrom::Common::Player GetPlayer();
	void WriteStateToController(Coding4Fun::Maelstrom::Communication::SocketListener^ listener);
	Coding4Fun::Maelstrom::Communication::GameStatePacket^ CreateGameStatePacket();

	void AttachPuck(int puck, Coding4Fun::Maelstrom::Common::Player player);
	void TurnOnCountdownLights(int index);
	void TurnOffCountdownLights(int index);
	void TurnOffAllCountdownLights();
	void PulseCountdownLights(int index, XMFLOAT4 color, float fadeUp, float duration, float fadeDown);
	void HandleNetwork();
	void HandleGameResults();
	void HandleGamePlaying();
	void HandlePowerupTiles();
	void ClearWallLights();
	void ClearWallTiles();
	void ResetGame();
	bool OnlyOnePuckActive();
	void DrawPaddlePower(Paddle^ paddle);
};

